#pragma once

#include<iostream>
#include<string>
#include<functional>
#include "Log.hpp"
#include "Connection.hpp"
#include "InetAddr.hpp"
#include "Reactor.hpp"

#define SIZE 1024
using namespace LogModule;

class Channel:public Connection
{
public:
    Channel(int sockfd,const InetAddr client_addr)
    :_sockfd(sockfd),_client_addr(client_addr)
    {
        SetNonBlock(sockfd);
    }

    void Recver() override
    {
        char buffer[SIZE];
        while(true)//用循环读保证把数据读完，用注册的方法来确保完整性（上层序列化处理）
        {
            buffer[0] = 0;
            ssize_t n = recv(_sockfd,buffer,sizeof(buffer)-1,0);
            if(n > 0)
            {
                buffer[n] = 0;
                _inbuffer += buffer;//写入接受缓冲区
            }
            else if(n == 0)
            {
                Excepter();
                return;
            }
            else 
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if(errno == EINTR)
                    continue;
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        //将inbuffer中的数据交给上层处理后发送应答
        LOG(LogLevel::DEBUG) << "Channel inbuffer:\n" << _inbuffer;
        if(!_inbuffer.empty())
            _outbuffer += _handler(_inbuffer);

        if(!_outbuffer.empty())
            Sender();
    }

    void Sender() override
    {
        while(true)
        {
            ssize_t n = send(_sockfd,_outbuffer.c_str(),_outbuffer.size(),0);
            if(n > 0)
            {
                _outbuffer.erase(0,n);
                if(_outbuffer.empty())
                    break;
            }
            else if(n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                if (errno == EINTR)
                    continue;
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        //上述循环已经将数据全部发送了
        //如果到这里outbuffer中还有数据，只可能是对端接受缓冲区满了
        //此时就需要开启对其写事件关心
        if(!_outbuffer.empty())
            GetOwner()->EnableReadOrWrite(_sockfd,true,true);
        else
            GetOwner()->EnableReadOrWrite(_sockfd,true,false);
    }

    void Excepter() override
    {
        //所有异常都归到了这个函数内部
        GetOwner()->DelConnection(_sockfd);
    }

    int GetSockfd() override
    {
        return _sockfd;
    }

    std::string& Inbuffer()
    {
        return _inbuffer;
    }

    void AppendOutBuffer(const std::string& out)
    {
        _outbuffer += out;
    }

    ~Channel(){}
private:
    //为什么普通sockfd就不用Socket的基类指针了？
    //因为这里我们自己管理缓冲区inbuffer/outbuffer来send
    //而不使用Socket里的send方法
    int _sockfd;
    std::string _inbuffer;
    std::string _outbuffer;
    InetAddr _client_addr;
};

